package com.bihua.iot.service.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.bihua.iot.domain.TdFields;
import com.bihua.iot.domain.TdSelect;
import com.bihua.iot.domain.TdSelectVisual;
import com.bihua.iot.domain.TdSuperTable;
import com.bihua.iot.domain.TdTable;
import com.bihua.iot.domain.TdTagsSelect;
import com.bihua.iot.mapper.TdEngineMapper;
import com.bihua.iot.service.TdEngineService;

import lombok.extern.slf4j.Slf4j;

/**
 * @ClassDescription: TdEngine业务层的实现层
 * @ClassName: TdEngineServiceImpl
 * @Author: thinglinks
 * @Date: 2021-12-27 13:55:49
 * @Version 1.0
 */
@Service
@Slf4j
@DS("td")
@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
public class TdEngineServiceImpl implements TdEngineService {

    @Autowired
    private TdEngineMapper tdEngineMapper;

    @Override
    @DS("td")
    public void createDateBase(String dataBaseName) throws Exception {
        this.tdEngineMapper.createDatabase(dataBaseName);
    }

    @Override
    @DS("td")
    public void createSuperTable(List<TdFields> schemaFields, List<TdFields> tagsFields, String dataBaseName, String superTableName) throws Exception {
        this.tdEngineMapper.createSuperTable(schemaFields, tagsFields, dataBaseName, superTableName);
    }

    @Override
    @DS("td")
    public void createTable(TdTable table) throws Exception {
        this.tdEngineMapper.createTable(table);
    }

    @Override
    @DS("td")
    public void insertData(TdTable table) throws Exception {
        this.tdEngineMapper.insertData(table);
    }

    @Override
    @DS("td")
    public List<Map<String, Object>> selectByTimesTamp(TdSelect select) {
        List<Map<String, Object>> maps = this.tdEngineMapper.selectByTimestamp(select);
        for (Map<String, Object> map : maps) {
            Map<String, Object> filterMap = map.entrySet()
                    .stream()
                    .filter(entry -> entry.getValue() != null)
                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        }
        return maps;
    }

    @Override
    @DS("td")
    public void addColumnForSuperTable(String superTableName, TdFields fields) throws Exception {
        this.tdEngineMapper.addColumnForSuperTable(superTableName, fields);
    }


    @Override
    @DS("td")
    public void dropColumnForSuperTable(String superTableName, TdFields fields) throws Exception {
        this.tdEngineMapper.dropColumnForSuperTable(superTableName, fields);
    }

    @Override
    @DS("td")
    public Long getCountByTimesTamp(TdSelect select) throws Exception {
        Map<String, Long> countMap = this.tdEngineMapper.getCountByTimestamp(select);
        if (countMap == null) {
            return 0L;
        }
        Long count = countMap.get("count");
        return count;
    }

    /**
     * 检查数据库表是否存在
     *
     * @param dataBaseName 数据库名
     * @param tableName    tableName 可以为超级表名或普通表名
     * @return
     */
    @Override
    @DS("td")
    public boolean checkTableExists(String dataBaseName, String tableName) {
        try {
            Integer count = tdEngineMapper.checkTableExists(dataBaseName, tableName);
            return count == 1;
        } catch (Exception e) {
            log.warn("{},{} 数据库表不存在", dataBaseName, tableName);
            return false;
        }
    }

    @Override
    @DS("td")
    public void initSTableFrame(String msg) throws Exception {
        final TdSuperTable superTable = JSONObject.toJavaObject(JSONObject.parseObject(msg), TdSuperTable.class);
        //从入参对象获取列字段（超级表结构）对象集合
        List<TdFields> schemaFields = superTable.getSchemaFields();
        //从入参对象获取标签字段对象集合
        List<TdFields> tagsFields = superTable.getTagsFields();
        //从入参获取数据库名称
        String dataBaseName = superTable.getDataBaseName();
        //从入参获取超级表名称
        String superTableName = superTable.getSuperTableName();
        final boolean tableExists = this.checkTableExists(dataBaseName, superTableName);
        if (tableExists) {
            log.info("超级表{}已存在", superTableName);
            return;
        }
        //获取列字段对象集合的第一个对象的字段数据类型
        String dataType = schemaFields.get(0).getDataType();
        //如果该数据类型不是时间戳，打印和返回报错信息
        if (dataType == null || !"timestamp".equals(dataType)) {
            log.error("invalid operation: first column must be timestamp");
            return;
        }
        //创建超级表
        this.createSuperTable(schemaFields, tagsFields, dataBaseName, superTableName);
        log.info("create {} super table success", superTableName);
    }

    /**
     * @param select
     * @return
     */
    @Override
    @DS("td")
    public List<Map<String, Object>> getLastData(TdSelect select){
        List<Map<String, Object>> maps = this.tdEngineMapper.getLastData(select);
//        for (Map<String, Object> map : maps) {
//            Map<String, Object> filterMap = map.entrySet()
//                    .stream()
//                    .filter(entry -> entry.getValue() != null)
//                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
//        }
        return maps;
    }

    /**
     * @param tagsSelect
     * @return
     */
    @Override
    @DS("td")
    public Map<String, Map<String, Object>> getLastDataByTags(TdTagsSelect tagsSelect) {
        List<Map<String, Object>> maps = this.tdEngineMapper.getLastDataByTags(tagsSelect);
        Map<String, Map<String, Object>> objectHashMap = new HashMap<>();
        for (Map<String, Object> map : maps) {
//            Map<String, Object> filterMap = map.entrySet()
//                    .stream()
//                    .filter(entry -> entry.getValue() != null)
//                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
            objectHashMap.put(map.get(tagsSelect.getTagsName()).toString(), map);
        }
        return objectHashMap;
    }


    @Override
    @DS("td")
    public List<Map<String, Object>> getHistoryData(TdSelectVisual selectVisual) {
        List<Map<String, Object>> maps = this.tdEngineMapper.getHistoryData(selectVisual);
        return maps;
    }

    @Override
    @DS("td")
    public List<Map<String, Object>> getRealtimeData(TdSelectVisual selectVisual) {
        List<Map<String, Object>> maps = this.tdEngineMapper.getRealtimeData(selectVisual);
        return maps;
    }

    @Override
    @DS("td")
    public List<Map<String, Object>> getAggregateData(TdSelectVisual selectVisual) {
        List<Map<String, Object>> maps = this.tdEngineMapper.getAggregateData(selectVisual);
        return maps;
    }

}
